package com.hotel.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hotel.entity.Reservation;
import com.hotel.entity.Room;
import com.hotel.entity.Member;
import com.hotel.dto.ReservationDTO;
import com.hotel.vo.ReservationVO;
import com.hotel.mapper.ReservationMapper;
import com.hotel.mapper.RoomMapper;
import com.hotel.mapper.MemberMapper;
import com.hotel.service.ReservationService;
import com.hotel.service.RoomService;
import com.hotel.service.MemberService;
import com.hotel.service.PointsRecordService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 预订服务实现类
 */
@Service
public class ReservationServiceImpl extends ServiceImpl<ReservationMapper, Reservation> implements ReservationService {
    
    @Autowired
    private ReservationMapper reservationMapper;
    
    @Autowired
    private RoomMapper roomMapper;
    
    @Autowired
    private MemberMapper memberMapper;
    
    @Autowired
    private RoomService roomService;
    
    @Autowired
    private MemberService memberService;
    
    @Autowired
    private PointsRecordService pointsRecordService;
    
    @Override
    public Page<ReservationVO> getReservationPage(int current, int size, String keyword, String status, 
                                                 String checkinDate, String checkoutDate) {
        Page<Reservation> page = new Page<>(current, size);
        
        LambdaQueryWrapper<Reservation> wrapper = new LambdaQueryWrapper<>();
        
        // 关键词搜索
        if (StringUtils.hasText(keyword)) {
            wrapper.and(w -> w.like(Reservation::getReservationNo, keyword)
                    .or().like(Reservation::getGuestName, keyword)
                    .or().like(Reservation::getGuestPhone, keyword));
        }
        
        // 状态过滤
        if (StringUtils.hasText(status)) {
            wrapper.eq(Reservation::getStatus, status);
        }
        
        // 入住日期过滤
        if (StringUtils.hasText(checkinDate)) {
            wrapper.ge(Reservation::getCheckinDate, LocalDate.parse(checkinDate));
        }
        
        // 退房日期过滤
        if (StringUtils.hasText(checkoutDate)) {
            wrapper.le(Reservation::getCheckoutDate, LocalDate.parse(checkoutDate));
        }
        
        wrapper.orderByDesc(Reservation::getCreateTime);
        
        Page<Reservation> reservationPage = this.page(page, wrapper);
        
        // 转换为VO
        Page<ReservationVO> voPage = new Page<>();
        BeanUtils.copyProperties(reservationPage, voPage);
        
        List<ReservationVO> voList = reservationPage.getRecords().stream().map(this::convertToVO).collect(Collectors.toList());
        
        voPage.setRecords(voList);
        return voPage;
    }
    
    @Override
    public ReservationVO getReservationById(Long id) {
        Reservation reservation = this.getById(id);
        if (reservation == null) {
            return null;
        }
        
        return convertToVO(reservation);
    }
    
    @Override
    @Transactional
    public boolean createReservation(ReservationDTO reservationDTO) {
        Reservation reservation = new Reservation();
        BeanUtils.copyProperties(reservationDTO, reservation);
        
        // 生成预订号
        reservation.setReservationNo(generateReservationNumber());
        
        // 计算住宿天数
        LocalDate checkinDate = reservation.getCheckinDate();
        LocalDate checkoutDate = reservation.getCheckoutDate();
        long nights = ChronoUnit.DAYS.between(checkinDate, checkoutDate);
        reservation.setNights((int) nights);
        
        // 设置状态为待确认
        reservation.setStatus("pending");
        
        // 设置创建时间和更新时间
        reservation.setCreateTime(LocalDateTime.now());
        reservation.setUpdateTime(LocalDateTime.now());
        
        boolean result = this.save(reservation);
        
        // 如果是会员预订，更新会员积分
        if (result && reservation.getMemberId() != null) {
            // 假设每消费100元获得1积分
            int points = reservation.getTotalAmount().intValue() / 100;
            if (points > 0) {
                memberService.updateMemberPoints(reservation.getMemberId(), points, 
                        "reservation", "预订奖励积分：" + reservation.getReservationNo());
            }
        }
        
        return result;
    }
    
    @Override
    @Transactional
    public boolean updateReservation(Long id, ReservationDTO reservationDTO) {
        Reservation reservation = this.getById(id);
        if (reservation == null) {
            return false;
        }
        
        // 只有待确认和已确认状态的预订可以修改
        if (!"pending".equals(reservation.getStatus()) && !"confirmed".equals(reservation.getStatus())) {
            return false;
        }
        
        BeanUtils.copyProperties(reservationDTO, reservation, "id", "reservationNo", "status", "createTime");
        
        // 重新计算住宿天数
        LocalDate checkinDate = reservation.getCheckinDate();
        LocalDate checkoutDate = reservation.getCheckoutDate();
        long nights = ChronoUnit.DAYS.between(checkinDate, checkoutDate);
        reservation.setNights((int) nights);
        
        reservation.setUpdateTime(LocalDateTime.now());
        
        return this.updateById(reservation);
    }
    
    @Override
    @Transactional
    public boolean cancelReservation(Long id, String reason) {
        Reservation reservation = this.getById(id);
        if (reservation == null) {
            return false;
        }
        
        // 只有待确认和已确认状态的预订可以取消
        if (!"pending".equals(reservation.getStatus()) && !"confirmed".equals(reservation.getStatus())) {
            return false;
        }
        
        int rows = reservationMapper.cancelReservation(id, reason, "system");
        
        // 如果是会员预订，扣减会员积分
        if (rows > 0 && reservation.getMemberId() != null) {
            // 假设取消预订扣减之前奖励的积分
            int points = reservation.getTotalAmount().intValue() / 100;
            if (points > 0) {
                memberService.updateMemberPoints(reservation.getMemberId(), -points, 
                        "cancel", "取消预订扣减积分：" + reservation.getReservationNo());
            }
        }
        
        return rows > 0;
    }
    
    @Override
    @Transactional
    public boolean confirmReservation(Long id) {
        Reservation reservation = this.getById(id);
        if (reservation == null) {
            return false;
        }
        
        // 只有待确认状态的预订可以确认
        if (!"pending".equals(reservation.getStatus())) {
            return false;
        }
        
        int rows = reservationMapper.confirmReservation(id, "system");
        return rows > 0;
    }
    
    @Override
    @Transactional
    public boolean checkin(Long reservationId, Long roomId) {
        Reservation reservation = this.getById(reservationId);
        if (reservation == null) {
            return false;
        }
        
        // 只有已确认状态的预订可以办理入住
        if (!"confirmed".equals(reservation.getStatus())) {
            return false;
        }
        
        // 检查房间是否可用
        Room room = roomService.getById(roomId);
        if (room == null || !"available".equals(room.getStatus())) {
            return false;
        }
        
        // 更新预订状态为已入住
        int reservationRows = reservationMapper.checkinReservation(reservationId, roomId, "system");
        
        // 更新房间状态为已占用
        boolean roomResult = roomService.updateRoomStatus(roomId, "occupied");
        
        return reservationRows > 0 && roomResult;
    }
    
    @Override
    @Transactional
    public boolean checkout(Long reservationId) {
        Reservation reservation = this.getById(reservationId);
        if (reservation == null) {
            return false;
        }
        
        // 只有已入住状态的预订可以办理退房
        if (!"checkedin".equals(reservation.getStatus())) {
            return false;
        }
        
        // 更新预订状态为已退房
        int reservationRows = reservationMapper.checkoutReservation(reservationId, "system");
        
        // 更新房间状态为清洁中
        Long roomId = reservation.getRoomId();
        boolean roomResult = true;
        if (roomId != null) {
            roomResult = roomService.updateRoomStatus(roomId, "cleaning");
        }
        
        // 如果是会员预订，更新会员消费记录和积分
        if (reservationRows > 0 && roomResult && reservation.getMemberId() != null) {
            // 更新会员总消费金额
            Member member = memberService.getById(reservation.getMemberId());
            if (member != null) {
                member.setTotalConsumption(member.getTotalConsumption().add(reservation.getTotalAmount()));
                memberService.updateById(member);
                
                // 假设每消费100元获得1积分（结算时再次奖励）
                int points = reservation.getTotalAmount().intValue() / 100;
                if (points > 0) {
                    memberService.updateMemberPoints(reservation.getMemberId(), points, 
                            "checkout", "退房结算奖励积分：" + reservation.getReservationNo());
                }
            }
        }
        
        return reservationRows > 0 && roomResult;
    }
    
    @Override
    public Reservation getReservationByNumber(String reservationNumber) {
        LambdaQueryWrapper<Reservation> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Reservation::getReservationNo, reservationNumber);
        return this.getOne(wrapper);
    }
    
    @Override
    public List<ReservationVO> getReservationsByCustomer(String customerName, String customerPhone) {
        List<Reservation> reservations = reservationMapper.getReservationsByCustomer(customerName, customerPhone);
        return reservations.stream().map(this::convertToVO).collect(Collectors.toList());
    }
    
    @Override
    public List<ReservationVO> getTodayCheckinReservations() {
        List<Reservation> reservations = reservationMapper.getTodayCheckinReservations();
        return reservations.stream().map(this::convertToVO).collect(Collectors.toList());
    }
    
    @Override
    public List<ReservationVO> getTodayCheckoutReservations() {
        List<Reservation> reservations = reservationMapper.getTodayCheckoutReservations();
        return reservations.stream().map(this::convertToVO).collect(Collectors.toList());
    }
    
    @Override
    public Map<String, Object> getReservationStats() {
        return reservationMapper.getReservationStats();
    }
    
    @Override
    public List<Map<String, Object>> getReservationTrend(String startDate, String endDate) {
        return reservationMapper.getReservationTrend(startDate, endDate);
    }
    
    @Override
    public Map<String, Object> getOccupancyRate(String startDate, String endDate) {
        return reservationMapper.getOccupancyRate(startDate, endDate);
    }
    
    @Override
    @Transactional
    public boolean extendStay(Long reservationId, String newCheckoutDate) {
        Reservation reservation = this.getById(reservationId);
        if (reservation == null) {
            return false;
        }
        
        // 只有已入住状态的预订可以延长住宿
        if (!"checkedin".equals(reservation.getStatus())) {
            return false;
        }
        
        // 检查房间在新的退房日期是否可用
        Long roomId = reservation.getRoomId();
        if (roomId != null) {
            LocalDate currentCheckoutDate = reservation.getCheckoutDate();
            LocalDate newCheckoutLocalDate = LocalDate.parse(newCheckoutDate);
            
            // 检查新的退房日期是否在当前退房日期之后
            if (newCheckoutLocalDate.isBefore(currentCheckoutDate) || newCheckoutLocalDate.isEqual(currentCheckoutDate)) {
                return false;
            }
            
            // 检查房间在延长期间是否已被预订
            String currentCheckoutDateStr = currentCheckoutDate.toString();
            int count = roomMapper.checkRoomAvailability(roomId, currentCheckoutDateStr, newCheckoutDate);
            if (count > 0) {
                return false;
            }
        }
        
        int rows = reservationMapper.extendStay(reservationId, newCheckoutDate);
        
        // 更新住宿天数和总金额
        if (rows > 0) {
            reservation = this.getById(reservationId);
            LocalDate checkinDate = reservation.getCheckinDate();
            LocalDate checkoutDate = reservation.getCheckoutDate();
            long nights = ChronoUnit.DAYS.between(checkinDate, checkoutDate);
            reservation.setNights((int) nights);
            
            // 重新计算总金额（简化处理，实际应该根据房型价格计算）
            // 这里假设每晚价格相同，根据原总金额和原住宿天数计算每晚价格，然后乘以新的住宿天数
            if (reservation.getTotalAmount() != null && reservation.getNights() > 0) {
                java.math.BigDecimal nightlyRate = reservation.getTotalAmount().divide(
                        java.math.BigDecimal.valueOf(reservation.getNights()), 2, java.math.RoundingMode.HALF_UP);
                java.math.BigDecimal newTotalAmount = nightlyRate.multiply(java.math.BigDecimal.valueOf(nights));
                reservation.setTotalAmount(newTotalAmount);
            }
            
            this.updateById(reservation);
        }
        
        return rows > 0;
    }
    
    @Override
    @Transactional
    public boolean changeRoom(Long reservationId, Long newRoomId) {
        Reservation reservation = this.getById(reservationId);
        if (reservation == null) {
            return false;
        }
        
        // 只有已入住状态的预订可以更换房间
        if (!"checkedin".equals(reservation.getStatus())) {
            return false;
        }
        
        // 检查新房间是否可用
        Room newRoom = roomService.getById(newRoomId);
        if (newRoom == null || !"available".equals(newRoom.getStatus())) {
            return false;
        }
        
        // 获取当前房间ID
        Long currentRoomId = reservation.getRoomId();
        
        // 更新预订的房间ID
        int rows = reservationMapper.changeRoom(reservationId, newRoomId);
        
        if (rows > 0) {
            // 更新新房间状态为已占用
            roomService.updateRoomStatus(newRoomId, "occupied");
            
            // 更新原房间状态为清洁中
            if (currentRoomId != null) {
                roomService.updateRoomStatus(currentRoomId, "cleaning");
            }
        }
        
        return rows > 0;
    }
    
    @Override
    public List<ReservationVO> getExpiringReservations(int hours) {
        List<Reservation> reservations = reservationMapper.getExpiringReservations(hours);
        return reservations.stream().map(this::convertToVO).collect(Collectors.toList());
    }
    
    @Override
    @Transactional
    public boolean batchConfirmReservations(List<Long> reservationIds) {
        if (reservationIds == null || reservationIds.isEmpty()) {
            return false;
        }
        
        for (Long id : reservationIds) {
            confirmReservation(id);
        }
        
        return true;
    }
    
    @Override
    public String generateReservationNumber() {
        String prefix = "R";
        String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        
        // 查询当天最大序号
        String pattern = prefix + timestamp + "%";
        LambdaQueryWrapper<Reservation> wrapper = new LambdaQueryWrapper<>();
        wrapper.likeRight(Reservation::getReservationNo, pattern)
                .orderByDesc(Reservation::getReservationNo)
                .last("LIMIT 1");
        
        Reservation lastReservation = this.getOne(wrapper);
        
        int sequence = 1;
        if (lastReservation != null) {
            String lastReservationNo = lastReservation.getReservationNo();
            String lastSequence = lastReservationNo.substring(lastReservationNo.length() - 4);
            sequence = Integer.parseInt(lastSequence) + 1;
        }
        
        return prefix + timestamp + String.format("%04d", sequence);
    }
    
    /**
     * 将Reservation实体转换为ReservationVO
     */
    private ReservationVO convertToVO(Reservation reservation) {
        ReservationVO vo = new ReservationVO();
        BeanUtils.copyProperties(reservation, vo);
        
        // 获取会员信息
        if (reservation.getMemberId() != null) {
            Member member = memberMapper.selectById(reservation.getMemberId());
            if (member != null) {
                vo.setCustomerName(member.getName());
            }
        }
        
        // 设置状态名称
        switch (reservation.getStatus()) {
            case "pending":
                vo.setStatusName("待确认");
                break;
            case "confirmed":
                vo.setStatusName("已确认");
                break;
            case "checkedin":
                vo.setStatusName("已入住");
                break;
            case "checkedout":
                vo.setStatusName("已退房");
                break;
            case "cancelled":
                vo.setStatusName("已取消");
                break;
            default:
                vo.setStatusName(reservation.getStatus());
        }
        
        return vo;
    }
}